using System;
using System.Collections.Generic;
using System.Text;
using MIMPGameLibrary;
using System.Collections.ObjectModel;

namespace MIMPWinForms.MIMPGameServices
{
    public class LocalGameStateController : IGameStateEventsService
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        #region IGameStateEventsService events and raisers
        /// <summary>
        /// Occurs when a new Monster is added to the game. EventData is the new Monster.
        /// </summary>
        public event EventHandler<EventArgs<Monster>> MonsterAdded;
        /// <summary>
        /// Occurs when a Monster is removed from the game. EventData is the removed Monster.
        /// </summary>
        public event EventHandler<EventArgs<Monster>> MonsterRemoved;
        /// <summary>
        /// Occurs when a Monster is moved to a different Hex. EventData is the Monster who moved 
        /// (use its Location property to get the Hex it moved to).
        /// </summary>
        public event EventHandler<EventArgs<Monster>> MonsterMoved;
        /// <summary>
        /// Occurs when the list of currently selected Monsters changes. EventData is the selected Monster.
        /// </summary>
        public event EventHandler<EventArgs<Monster>> SelectedMonsterChanged;
        /// <summary>
        /// Occurs when the user has chosen a target to attack, and should now select additional attackers. 
        /// EventData is the Monster being targeted.
        /// </summary>
        public event EventHandler<EventArgs<Monster>> AttackTargetChosen;
        /// <summary>
        /// Occurs when the list of monsters preparing to attack the target changes. 
        /// </summary>
        public event EventHandler<EventArgs<List<Monster>>> AttackersChanged;
        /// <summary>
        /// Occurs when the list of monsters assisting in defense changes. 
        /// </summary>
        public event EventHandler<EventArgs<List<Monster>>> DefendersChanged;
        /// <summary>
        /// Occurs when the attacking player has finished selecting all attackers, and the defending player should now select defenders.
        /// PrimaryEventData is the list of attacking monsters. SecondaryEventData is the target of the attack.
        /// </summary>
        public event EventHandler<EventArgs<List<Monster>, Monster>> AttackersFinalized;
        /// <summary>
        /// Occurs when the game has determined who won and lost the attack; at this point the losing player must
        /// decide how to divide the damage up among his Monsters. EventData is an AttackResult object describing 
        /// the outcome of the attack.
        /// </summary>
        public event EventHandler<EventArgs<AttackResult>> AttackResultCalculated;
        /// <summary>
        /// Occurs when the attack has been completed and damage assigned to the losing Monsters.
        /// EventData is a list of all Monsters who took damage in the attack.
        /// </summary>
        public event EventHandler<EventArgs<List<Monster>>> AttackCompleted;
        /// <summary>
        /// Occurs when an action the user attempted to take failed.
        /// EventData is a string explaining the error.
        /// </summary>
        public event EventHandler<EventArgs<string>> ActionFailed;
        /// <summary>
        /// Occurs whenever one of the game's ControlPoints is updated with a new owner or a new control strength.
        /// EventData is the ControlPoint that changed.
        /// </summary>
        public event EventHandler<EventArgs<ControlPoint>> ControlPointChanged;
        /// <summary>
        /// Occurs when one Player's turn ends and the next's begins. EventData is the Player whose turn just started.
        /// </summary>
        public event EventHandler<EventArgs<Player>> NewTurnBegan;
        /// <summary>
        /// Occurs when a Player is eliminated from the game. EventData is the Player who lost.
        /// </summary>
        public event EventHandler<EventArgs<Player>> PlayerLost;
        /// <summary>
        /// Occurs when someone wins the game. EventData is the Player who won.
        /// </summary>
        public event EventHandler<EventArgs<Player>> PlayerWon;
        /// <summary>
        /// Occurs when a Monster uses an action to get a second move. EventData is the Monster in question.
        /// </summary>
        public event EventHandler<EventArgs<Monster>> MonsterTookSecondMove;
        /// <summary>
        /// Occurs when control of the game state updates passes to a different Player. EventData is the Player who now has control.
        /// </summary>
        public event EventHandler<EventArgs<Player>> ActivePlayerChanged;
        /// <summary>
        /// Occurs when the number of deployment points a Player has left changes. 
        /// EventData is the Player whose points changed; to get the number of points he/she now has, use Player.DeploymentPoints.
        /// </summary>
        public event EventHandler<EventArgs<Player>> PlayersDeploymentPointsChanged;
        /// <summary>
        /// Occurs when the game phase changes. EventData is the phase the game is now in.
        /// </summary>
        public event EventHandler<EventArgs<GameState.Phases>> GamePhaseChanged;
        /// <summary>
        /// Occurs when the Hexes that make up the game map change. EventData is a List of the Hexes that are now in the game.
        /// </summary>
        public event EventHandler<EventArgs<List<Hex>>> MapChanged;
        /// <summary>
        /// Occurs when the game sends a message that should be displayed to the players. 
        /// EventData is a string containing the message to display.
        /// </summary>
        public event EventHandler<EventArgs<string>> ApplicationMessageSent;
        /// <summary>
        /// Occurs when a player sends a chat message that should be displayed to all players. 
        /// PrimaryEventData is the Player who sent the message.
        /// SecondaryEventData is a string containing the message sent.
        /// </summary>
        public event EventHandler<EventArgs<Player, string>> ChatYellSent;
        /// <summary>
        /// Occurs when a player sends a chat message that should be displayed to a group of players.
        /// PrimaryEventData is the Player who sent the message.
        /// SecondaryEventData is a string containing the message sent.
        /// TertiaryEventData is a List of Players who should see the message.
        /// </summary>
        public event EventHandler<EventArgs<Player, string, List<Player>>> ChatSaySent;
        /// <summary>
        /// Occurs when a player sends a message that should be dispalyed to only one other player.
        /// PrimaryEventData is the Player who sent the message.
        /// SecondaryEventData is a string containing the message sent.
        /// TertiaryEventData is the Player who should see the message.
        /// </summary>
        public event EventHandler<EventArgs<Player, string, Player>> ChatWhisperSent;


        protected virtual void RaiseMonsterAdded(Monster added) {
            if (MonsterAdded != null) {
                MonsterAdded(this, new EventArgs<Monster>(added));
            }
        }

        protected virtual void RaiseMonsterRemoved(Monster removed) {
            if (MonsterRemoved != null) {
                MonsterRemoved(this, new EventArgs<Monster>(removed));
            }
        }

        protected virtual void RaiseMonsterMoved(Monster moved) {
            if (MonsterMoved != null) {
                MonsterMoved(this, new EventArgs<Monster>(moved));
            }
        }

        protected virtual void RaiseSelectedMonsterChanged(Monster changed) {
            if (SelectedMonsterChanged != null) {
                SelectedMonsterChanged(this, new EventArgs<Monster>(changed));
            }
        }

        protected void RaiseAttackTargetChosen(Monster target) {
            if (AttackTargetChosen != null) {
                if (log.IsInfoEnabled) log.Info("Raising AttackTargetChosen with " + target);
                AttackTargetChosen(this, new EventArgs<Monster>(target));
            }
        }

        protected void RaiseDefendersChanged(List<Monster> defenders) {
            if (DefendersChanged != null) {
                if (log.IsInfoEnabled) log.Info("Raising DefendersChanged with " + defenders);
                DefendersChanged(this, new EventArgs<List<Monster>>(defenders));
            }
        }

        protected void RaiseAttackersChanged(List<Monster> attackers) {
            if (AttackersChanged != null) {
                if (log.IsInfoEnabled) log.Info("Raising AttackersChanged with " + attackers);
                AttackersChanged(this, new EventArgs<List<Monster>>(attackers));
            }
        }

        protected void RaiseAttackersFinalized(List<Monster> attackers, Monster target) {
            if (AttackersFinalized != null) {
                if (log.IsInfoEnabled) log.Info("Raising AttackersFinalized");
                AttackersFinalized(this, new EventArgs<List<Monster>, Monster>(attackers, target));
            }
        }

        protected virtual void RaiseAttackResultCalculated(AttackResult result) {
            if (AttackResultCalculated != null) {
                if (log.IsInfoEnabled) log.Info("Raising attack result calculated with " + result);
                AttackResultCalculated(this, new EventArgs<AttackResult>(result));
            }
        }

        protected virtual void RaiseAttackCompleted(List<Monster> losers) {
            if (AttackCompleted != null) {
                AttackCompleted(this, new EventArgs<List<Monster>>(losers));
            }
        }

        protected virtual void RaiseActionFailed(string errorReason) {
            if (ActionFailed != null) {
                ActionFailed(this, new EventArgs<string>(errorReason));
            }
        }

        protected virtual void RaiseControlPointChanged(ControlPoint changed) {
            if (ControlPointChanged != null) {
                ControlPointChanged(this, new EventArgs<ControlPoint>(changed));
            }
        }

        protected virtual void RaiseNewTurnBegan(Player active) {
            if (NewTurnBegan != null) {
                NewTurnBegan(this, new EventArgs<Player>(active));
            }
        }

        protected virtual void RaisePlayerLost(Player loser) {
            if (PlayerLost != null) {
                PlayerLost(this, new EventArgs<Player>(loser));
            }
        }

        protected virtual void RaisePlayerWon(Player winner) {
            if (PlayerWon != null) {
                PlayerWon(this, new EventArgs<Player>(winner));
            }
        }

        protected virtual void RaiseMonsterTookSecondMove(Monster actor) {
            if (MonsterTookSecondMove != null) {
                MonsterTookSecondMove(this, new EventArgs<Monster>(actor));
            }
        }

        protected virtual void RaiseActivePlayerChanged(Player active) {
            if (ActivePlayerChanged != null) {
                ActivePlayerChanged(this, new EventArgs<Player>(active));
            }
        }

        protected virtual void RaisePlayersDeploymentPointsChanged(Player changed) {
            if (PlayersDeploymentPointsChanged != null) {
                PlayersDeploymentPointsChanged(this, new EventArgs<Player>(changed));
            }
        }

        protected virtual void RaiseGamePhaseChanged(GameState.Phases newPhase) {
            if (GamePhaseChanged != null) {
                GamePhaseChanged(this, new EventArgs<GameState.Phases>(newPhase));
            }
        }

        protected virtual void RaiseMapChanged(List<Hex> map) {
            if (MapChanged != null) {
                MapChanged(this, new EventArgs<List<Hex>>(map));
            }
        }

        protected virtual void RaiseApplicationMessageSent(string message) {
            if (ApplicationMessageSent != null) {
                ApplicationMessageSent(this, new EventArgs<string>(message));
            }
        }

        protected virtual void RaiseChatYellSent(Player yeller, string message) {
            if (ChatYellSent != null) {
                ChatYellSent(this, new EventArgs<Player, string>(yeller, message));
            }
        }

        protected virtual void RaiseChatSaySent(Player speaker, string message, List<Player> audience) {
            if (ChatSaySent != null) {
                ChatSaySent(this, new EventArgs<Player, string, List<Player>>(speaker, message, audience));
            }
        }

        protected virtual void RaiseChatWhisperSent(Player whisperer, string message, Player listener) {
            if (ChatWhisperSent != null) {
                ChatWhisperSent(this, new EventArgs<Player, string, Player>(whisperer, message, listener));
            }
        }
        #endregion

        IControlPanelEventsService controlPanel;
        IGameScreenEventsService screen;
        GameState state;

        enum Activities { None, Deploying, Deleting, Moving, Attacking, AddingAttackers, Casting, Defending };
        Activities activity = Activities.None;
        Monster active;

        /// <summary>
        /// A list of the Players currently in the game.
        /// </summary>
        public ReadOnlyCollection<Player> Players {
            get { return state.Players.AsReadOnly(); }
        }
        /// <summary>
        /// A list of the Hexes in the game.
        /// </summary>
        public List<Hex> Hexes {
            get {
                if (state != null) {
                    return new List<Hex>(state.HexList);
                } else {
                    return null;
                }
            }
        }

        public LocalGameStateController(GameState gameState) {
            state = gameState;
        }

        public void SetService(ServiceProvider gameServices) {
            controlPanel = (IControlPanelEventsService)(gameServices.GetService(typeof(IControlPanelEventsService)));
            screen = (IGameScreenEventsService)(gameServices.GetService(typeof(IGameScreenEventsService)));
            controlPanel.ChatTextEntered += new EventHandler<EventArgs<string>>(controlPanel_ChatTextEntered);
            controlPanel.EndTurnButtonClicked += new EventHandler(controlPanel_EndTurnButtonClicked);
            controlPanel.AddNewMonsterButtonClicked += new EventHandler<EventArgs<Monster>>(controlPanel_AddNewMonsterButtonClicked);
            controlPanel.CancelButtonClicked += new EventHandler(controlPanel_CancelButtonClicked);
            controlPanel.DeleteMonsterButtonClicked += new EventHandler(controlPanel_DeleteMonsterButtonClicked);
            controlPanel.MoveButtonClicked += new EventHandler(controlPanel_MoveButtonClicked);
            controlPanel.SecondMoveButtonClicked += new EventHandler(controlPanel_SecondMoveButtonClicked);
            controlPanel.AttackButtonClicked += new EventHandler(controlPanel_AttackButtonClicked);
            controlPanel.DoneButtonClicked += new EventHandler(controlPanel_DoneButtonClicked);
            controlPanel.DamageAssigned += new EventHandler<EventArgs<Dictionary<Monster, int>>>(controlPanel_DamageAssigned);
            screen.HexLeftClicked += new EventHandler<EventArgs<Hex, System.Windows.Forms.Keys>>(screen_HexLeftClicked);
        }

        void controlPanel_DamageAssigned(object sender, EventArgs<Dictionary<Monster, int>> e) {
            if (log.IsInfoEnabled) log.Info("Entered controlPanel_DamageAssigned");
            if (activity == Activities.Defending) {
                activity = Activities.None;
                List<Monster> updated = state.CompleteAttack(e.EventData);
                RaiseAttackCompleted(updated);
            }
            if (log.IsInfoEnabled) log.Info("Exiting controlPanel_DamageAssigned");
        }

        void controlPanel_DoneButtonClicked(object sender, EventArgs e) {
            if (log.IsInfoEnabled) log.Info("Entered controlPanel_DoneButtonClicked");
            if (activity == Activities.AddingAttackers) {
                if (log.IsDebugEnabled) log.Debug("Setting active player to " + state.Target.Controller);
                activity = Activities.Defending;
                RaiseActivePlayerChanged(state.Target.Controller);
                List<Monster> allattackers = new List<Monster>(state.Attackers);
                allattackers.Add(state.Selected);
                RaiseAttackersFinalized(allattackers, state.Target);
            } else if (activity == Activities.Defending) {
                if (log.IsDebugEnabled) log.Debug("Done defending");
                try {
                    AttackResult result = state.BeginAttack();
                    RaiseAttackResultCalculated(result);
                    if (result.TotalDamageDone == 0) {
                        RaiseAttackCompleted(new List<Monster>());
                    }
                } catch (Exception ex) {
                    if (log.IsErrorEnabled) log.Error("Caught exception in gameState.BeginAttack:" + ex);
                    activity = Activities.None;
                    RaiseActionFailed("Error trying to calculate attack result.");
                }
            }
            if (log.IsInfoEnabled) log.Info("Exiting controlPanel_DoneButtonClicked");
        }

        void controlPanel_AttackButtonClicked(object sender, EventArgs e) {
            if (log.IsInfoEnabled) log.Info("Entered controlPanel_AttackButtonClicked");
            if (!state.IsSelected) {
                RaiseActionFailed("Select a monster to attack with first.");
            } else if (activity == Activities.None) {
                activity = Activities.Attacking;
                state.Target = null;
            } else {
                RaiseActionFailed("You cannot begin an attack while another action is pending.");
            }
            if (log.IsInfoEnabled) log.Info("Exiting controlPanel_AttackButtonClicked");
        }

        void controlPanel_SecondMoveButtonClicked(object sender, EventArgs e) {
            if (log.IsInfoEnabled) log.Info("Entered controlPanel_SecondMoveButtonClicked");
            if (activity == Activities.None) {
                try {
                    state.SecondMove();
                } catch (IllegalActionException ex) {
                    if (log.IsDebugEnabled) log.Debug("Caught IllegalActionException", ex);
                    RaiseActionFailed(ex.Message);
                }
                RaiseMonsterTookSecondMove(state.Selected);
            } else {
                if (log.IsDebugEnabled) log.Debug("Tried to take second move while activity was " + Enum.GetName(typeof(Activities), activity));
                RaiseActionFailed("You cannot take a second move while another action is pending.");
            }
            if (log.IsInfoEnabled) log.Info("Exiting controlPanel_SecondMoveButtonClicked");
        }

        void controlPanel_MoveButtonClicked(object sender, EventArgs e) {
            if (!state.IsSelected) {
                RaiseActionFailed("Select a monster to move first.");
            } else if (activity == Activities.None) {
                activity = Activities.Moving;
            } else {
                RaiseActionFailed("You cannot move while another action is pending.");
            }
        }

        void controlPanel_DeleteMonsterButtonClicked(object sender, EventArgs e) {
            activity = Activities.Deleting;
        }

        void controlPanel_CancelButtonClicked(object sender, EventArgs e) {
            if (log.IsInfoEnabled) log.Info("Entered controlPanel_CancelButtonClicked");
            switch (activity) {
                case Activities.Deploying:
                    active = null;
                    activity = Activities.None;
                    if (log.IsInfoEnabled) log.Info("Canceling deployment");
                    RaiseActionFailed("Canceled deployment by user request.");
                    break;
                case Activities.Deleting:
                    active = null;
                    activity = Activities.None;
                    if (log.IsInfoEnabled) log.Info("Canceling deletion");
                    RaiseActionFailed("Canceled monster deletion by user request.");
                    break;
                case Activities.Moving:
                    active = null;
                    activity = Activities.None;
                    if (log.IsInfoEnabled) log.Info("Canceling move");
                    RaiseActionFailed("Canceled movement by user request.");
                    break;
                case Activities.Attacking:
                case Activities.AddingAttackers:
                    active = null;
                    activity = Activities.None;
                    if (log.IsInfoEnabled) log.Info("Canceling attack");
                    RaiseActionFailed("Canceled attack by user request.");
                    break;
            }
            if (log.IsInfoEnabled) log.Info("Exiting controlPanel_CancelButtonClicked");
        }

        void screen_HexLeftClicked(object sender, EventArgs<Hex, System.Windows.Forms.Keys> e) {
            if (log.IsInfoEnabled) log.Info("Entered screen_HexLeftClicked");
            if (log.IsInfoEnabled) log.Info("Activity is: " + Enum.GetName(typeof(Activities), activity));
            if (log.IsInfoEnabled) log.Info("EventArgs: primary=[" + e.PrimaryEventData + "], secondary=[" + e.SecondaryEventData + "]");
            switch (activity) {
                case Activities.Deploying:
                    try {
                        if (log.IsDebugEnabled) log.Debug("Deploying " + active);
                        state.DeployMonster(active, e.PrimaryEventData);
                        RaiseMonsterAdded(active);
                        RaisePlayersDeploymentPointsChanged(state.ActivePlayer);
                    } catch (IllegalDeploymentException ex) {
                        if (log.IsDebugEnabled) log.Debug("Caught IllegalDeploymentException", ex);
                        RaiseActionFailed(ex.Message);
                    } finally {
                        active = null;
                        activity = Activities.None;
                    }
                    break;
                case Activities.Deleting:
                    if (e.PrimaryEventData.IsMonsterOn) {
                        Monster removed = e.PrimaryEventData.MonsterOn;
                        if (log.IsDebugEnabled) log.Debug("Found monster " + removed + " on the hex. Undeploying it.");
                        state.UndeployMonster(removed);
                        RaiseMonsterRemoved(removed);
                        RaisePlayersDeploymentPointsChanged(state.ActivePlayer);
                        active = null;
                        activity = Activities.None;
                    }
                    break;
                case Activities.Moving:
                    try {
                        if (log.IsDebugEnabled) log.Debug("Moving selected monster.");
                        state.Move(e.PrimaryEventData);
                        RaiseMonsterMoved(e.PrimaryEventData.MonsterOn);
                        active = null;
                        activity = Activities.None;
                    } catch (IllegalMoveException ex) {
                        if (log.IsDebugEnabled) log.Debug("Caught IllegalMoveException", ex);
                        RaiseActionFailed(ex.Message);
                    }
                    break;
                case Activities.Attacking:
                    if (e.PrimaryEventData.IsMonsterOn) {
                        try {
                            if (log.IsDebugEnabled) log.Debug("Making clicked monster the attack target.");
                            state.Target = e.PrimaryEventData.MonsterOn;
                            activity = Activities.AddingAttackers;
                            RaiseAttackTargetChosen(state.Target);
                        } catch (IllegalSelectionException ex) {
                            activity = Activities.None;
                            if (log.IsWarnEnabled) log.Warn("Caught IllegalSelectionException:", ex);
                            RaiseActionFailed(ex.Message);
                        }
                    }
                    break;
                case Activities.AddingAttackers:
                    if (e.PrimaryEventData.IsMonsterOn) {
                        //control held down = remove from list
                        if ((e.SecondaryEventData & System.Windows.Forms.Keys.Control) != 0) {
                            if (log.IsDebugEnabled) log.Debug("Control held down while clicking. Removing from attackers list.");
                            state.RemoveAttacker(e.PrimaryEventData.MonsterOn);
                            RaiseAttackersChanged(state.Attackers);
                        } else {
                            //control not held down = add to list
                            try {
                                if (log.IsDebugEnabled) log.Debug("Adding monster on clicked hex to attackers.");
                                state.AddAttacker(e.PrimaryEventData.MonsterOn);
                                RaiseAttackersChanged(state.Attackers);
                            } catch (IllegalSelectionException ex) {
                                if (log.IsWarnEnabled) log.Warn("Caught IllegalSelectionException:", ex);
                                activity = Activities.None;
                                RaiseActionFailed(ex.Message);
                            }
                        }
                    }
                    break;
                case Activities.Defending:
                    if (e.PrimaryEventData.IsMonsterOn) {
                        //control held down = remove from list
                        if ((e.SecondaryEventData & System.Windows.Forms.Keys.Control) != 0) {
                            if (log.IsDebugEnabled) log.Debug("Control held down while clicking. Removing from defenders list.");
                            state.RemoveDefender(e.PrimaryEventData.MonsterOn);
                            RaiseDefendersChanged(state.Defenders);
                        } else {
                            //control not held down = add to list
                            try {
                                if (log.IsDebugEnabled) log.Debug("Adding monster on clicked hex to defenders.");
                                state.AddDefender(e.PrimaryEventData.MonsterOn);
                                RaiseDefendersChanged(state.Defenders);
                            } catch (IllegalSelectionException ex) {
                                if (log.IsWarnEnabled) log.Warn("Caught IllegalSelectionException:", ex);
                                //unlike most other cases, do NOT want to modify activity here. 
                                //user must keep selecting defenders until Done is clicked.
                                RaiseActionFailed(ex.Message);
                            }
                        }
                    }
                    break;
                case Activities.None:
                    if (e.PrimaryEventData.IsMonsterOn) {
                        try {
                            if (log.IsDebugEnabled) log.Debug("Selecting monster on hex.");
                            active = state.Selected = e.PrimaryEventData.MonsterOn;
                            RaiseSelectedMonsterChanged(state.Selected);
                        } catch (IllegalSelectionException ex) {
                            if (log.IsDebugEnabled) log.Debug("Caught IllegalSelectionException (not raising an error message).", ex);
                        }
                    }
                    break;
            }
            if (log.IsInfoEnabled) log.Info("Exiting screen_HexLeftClicked");
        }

        void controlPanel_AddNewMonsterButtonClicked(object sender, EventArgs<Monster> e) {
            if (log.IsInfoEnabled) log.Info("Entered controlPanel_AddNewMonsterButtonClicked");
            active = e.EventData;
            activity = Activities.Deploying;
            if (log.IsInfoEnabled) log.Info("Exiting controlPanel_AddNewMonsterButtonClicked");
        }

        void controlPanel_EndTurnButtonClicked(object sender, EventArgs e) {
            if (log.IsInfoEnabled) log.Info("Entered controlPanel_EndTurnButtonClicked");
            if (activity != Activities.None) {
                if (log.IsWarnEnabled) log.Warn("Attempted to end turn while activity was: " + Enum.GetName(typeof(Activities), activity));
                RaiseActionFailed("The turn cannot end while an action is pending.");
                return;
            }

            if (state.Phase == GameState.Phases.Setup) {
                if (log.IsDebugEnabled) log.Debug("Currently in Setup Phase.");
                if (state.ActivePlayer == state.Players[state.Players.Count - 1]) {
                    if (log.IsInfoEnabled) log.Info("All players are set up. Beginning the Play Phase.");
                    state.EndSetupPhase();
                    RaiseGamePhaseChanged(state.Phase);
                } else {
                    if (log.IsDebugEnabled) log.Debug("Calling SetupNextPlayer");
                    state.SetupNextPlayer();
                }
                if (log.IsInfoEnabled) log.Info("Active player is now " + state.ActivePlayer);
                RaiseActivePlayerChanged(state.ActivePlayer);
                RaiseNewTurnBegan(state.ActivePlayer);
                RaisePlayersDeploymentPointsChanged(state.ActivePlayer);
            } else {
                if (log.IsDebugEnabled) log.Debug("Currently in the Play Phase.");
                List<ControlPoint> changedCPs = new List<ControlPoint>(state.EndTurn());
                if (log.IsInfoEnabled) log.Info("Active player is now " + state.ActivePlayer);
                if (changedCPs.Count > 0) {
                    foreach (ControlPoint cp in changedCPs) {
                        RaiseControlPointChanged(cp);
                    }
                }
                RaiseActivePlayerChanged(state.ActivePlayer);
                RaiseNewTurnBegan(state.ActivePlayer);
            }
            if (log.IsInfoEnabled) log.Info("Exiting controlPanel_EndTurnButtonClicked");
        }

        public void StartGame() {
            if (log.IsInfoEnabled) log.Info("Entered StartGame");
            RaiseActivePlayerChanged(state.ActivePlayer);
            RaiseGamePhaseChanged(state.Phase);
            RaisePlayersDeploymentPointsChanged(state.ActivePlayer);
            if (log.IsInfoEnabled) log.Info("Exiting StartGame");
        }

        void controlPanel_ChatTextEntered(object sender, EventArgs<string> e) {
            RaiseChatYellSent(state.ActivePlayer, e.EventData);
        }
    }
}
